<?php

/**
 *  钉钉登录逻辑
 */

namespace app\admin\service;


use app\common\exception\ThrowException;
use app\facade\Basic;
use app\admin\model\Operator;
use think\facade\Config;
use app\admin\model\Department as ModelDepartment;
use think\facade\Db;

class Dingtalk extends BaseService
{

    protected $client_id;
    protected $client_secret;
    protected $redirect_uri;
    protected $access_token;
    protected $refresh_data;
    protected $userid;
    protected $user_data;
    protected $department = [];
    protected $ip;



    public function __construct()
    {
        parent::__construct();
        // client_id
        $this->client_id = Config::get('dingtalk.clientId');
        // client_secret
        $this->client_secret = Config::get('dingtalk.clientSecret');
        //回调链接
        $env = env('APP_ENV') ?? 'prod';
        $url = Config::get('domain')[$env]['erpapi'] . "/admin/dingtalk/callback";
        $this->redirect_uri = urlencode($url);
    }


    /**
     * 用户登录
     * @return string
     * @throws \Exception
     */
    public function getCode()
    {
        $url = "https://login.dingtalk.com/oauth2/auth?redirect_uri={$this->redirect_uri}&response_type=code&client_id={$this->client_id}&scope=openid&prompt=consent";
        header('Location:' . $url);
    }


    /**
     *  用户登录
     */

    public function login($param)
    {

        // $result = Operator::where('id','12')->find();
        // /* 登录逻辑 */
        // return $this->go_login($result);
        // /* -1111 */

        if (empty($param['authCode'])) {
            throw new ThrowException([
                'message' => 'auth Code is required'
            ]);

        }

        $this->ip = $param['ip'];


        // 获取 accessToken
        $this->access_token = $this->get_user_token($param['authCode']);

        // 获取用户信息
        $this->refresh_data = $this->get_user_data($this->access_token);

        if (!$this->refresh_data) {
            return Basic::data(0, '登录失败');
        }

        $result = Operator::where('openId', $this->refresh_data['openId'])->where('is_del','0')->find();


        if ($result) {

            /* 判断是否限制登录 */
            if ($result->status != 1) {
                return Basic::data(0, '该用户被限制登录');
            }


            /* 登录逻辑 */
            return $this->go_login($result);

        } else {
            /* 新用户创建 */
            $new_user = $this->new_user();
            return $this->go_login($new_user);
        }
    }


    /**
     *  创建员工信息
     */
    public function new_user()
    {

        /* 获取钉钉 access_token */
        $this->access_token = $this->get_access_token();

        /* 获取钉钉userID */
        $this->userid = $this->getUseridByUnionid();

        /* 获取钉钉用户信息 */
        $this->user_data =  $this->getUserdataByUserid();

        /* 获取钉钉职位列表 */
        $departmentList = $this->getDepartmentList();

        // 查询部门
        $department = $this->getDepartment($departmentList);


        $new_user = [];
        $new_user['cname'] = ($this->user_data)['name'];
        $new_user['phone'] = isset($this->refresh_data['mobile']) ? $this->refresh_data['mobile'] : '';
        $new_user['email'] = isset($this->refresh_data['email']) ? $this->refresh_data['email'] : '';
        $new_user['nickname'] = ($this->user_data)['name'];

        $new_user['userid'] = $this->userid;

        $new_user['department'] = isset($department['id']) ? $department['id'] : '';
        $new_user['position'] = ($this->user_data)['position'];

        $new_user['create_time'] = date('Y-m-d H:i:s', time());
        $new_user['status'] = 1;
        $new_user['isadmin'] = 0;

        $new_user['openId'] = ($this->refresh_data)['openId'];
        $new_user['unionId'] = ($this->refresh_data)['unionId'];

        $new_user['is_login'] = 1;
        $new_user['login_status'] = 1;

        $user_result = Operator::create($new_user);

        if ($user_result) {
            $this->logger->logOperation($user_result->id,'Dingtalk','员工注册','员工注册成功');
            return $user_result;
        } else {
            return Basic::data(0, '创建用户失败');
        }
    }

    /**
     *  获取用户 Token
     */
    public function get_user_token($authCode)
    {
        $data = json_encode(array(
            'clientId' => $this->client_id,
            'clientSecret' => $this->client_secret,
            'code' => $authCode,
            'grantType' => 'authorization_code'
        ));

        // 设置 CURLOPT_POSTFIELDS 选项为该字符串本身
        $options = array(
            CURLOPT_URL => 'https://api.dingtalk.com/v1.0/oauth2/userAccessToken',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $data,
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json'
            )
        );


        // 创建一个 curl 句柄
        $ch = curl_init();

        // 设置 curl 选项
        curl_setopt_array($ch, $options);

        // 执行 curl 请求
        $response = curl_exec($ch);

        $result = json_decode($response, true);

        if(!isset($result)) {
            throw new ThrowException([
                'message' => '钉钉登录失败'
            ]);
        }

        if (!isset($result['accessToken'])) {
            throw new ThrowException([
                'message' => '钉钉登录失败'
            ]);
        }

        $accessToken = $result['accessToken'];

        // 关闭 curl 句柄
        curl_close($ch);
        return $accessToken;
    }


    public function get_user_data($userToken)
    {
        // 初始化Curl
        $ch = curl_init();

        // 设置URL和参数
        $url = 'https://api.dingtalk.com/v1.0/contact/users/me';

        // 设置请求头信息
        $headers = array(
            'x-acs-dingtalk-access-token: ' . $userToken,
            'Content-Type:application/json'
        );
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        // 设置Curl选项
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // 执行Curl请求
        $response = curl_exec($ch);

        $result = json_decode($response, true);

        if(!isset($result)) {
            throw new ThrowException([
                'message' => 'auth Code is required'
            ]);
        }

        // 检查是否有错误发生
        if (curl_errno($ch)) {
            throw new ThrowException([
                'message' => curl_error($ch)
            ]);
        }

        // 关闭Curl请求
        curl_close($ch);

        // 处理响应数据
        return $result;
    }


    /**
     *  获取钉钉userid
     */
    public function getUseridByUnionid()
    {

        $access_token = $this->access_token;
        $unionid = $this->refresh_data['unionId'];
        $url = "https://oapi.dingtalk.com/user/getUseridByUnionid?access_token={$access_token}&unionid={$unionid}";
        $response = file_get_contents($url);

        $response_data = json_decode($response, true);
        if ($response_data['errcode'] != 0) {
            throw new ThrowException([
                'message' => '获取钉钉 userid 错误'
            ]);
        }

        return $response_data['userid'];
    }

    /**
     *  用户登录
     */
    public function go_login($user)
    {

        $token = new Token();
        $token = $token->get($user);

        /* 更新登陆信息 */
        $user->login_num = ($user->login_num + 1);
        $user->last_login_time = date("Y-m-d H:i:s", time());
        $user->last_ip = $this->ip;
        $user->save();

        $userinfo = [
            'id' => $user->id,
            'username' => $user->cname,
            'isadmin' => $user->isadmin,
            'role' => $user->roles,
            'token' => $token
        ];

        $this->logger->logOperation($user->id,'Dingtalk','登录','用户登录');

        return Basic::data(1, '登录成功', $userinfo);
    }


    /**
     *  获取 access_token
     */
    public function get_access_token()
    {

        $clientId = $this->client_id;
        $clientSecret = $this->client_secret;
        $url = "https://oapi.dingtalk.com/gettoken?corpid={$clientId}&corpsecret={$clientSecret}";
        $response = file_get_contents($url);

        $response_data = json_decode($response, true);
        if ($response_data['errcode'] != 0) {
            throw new ThrowException([
                'message' => '获取钉钉 access_token 错误'
            ]);
        }

        return $response_data['access_token'];
    }

    /**
     *  获取钉钉用户信息
     */
    public function getUserdataByUserid()
    {
        $access_token = $this->access_token;
        $userid = $this->userid;
        $url = "https://oapi.dingtalk.com/user/get?access_token={$access_token}&userid={$userid}";
        $response = file_get_contents($url);

        /* 钉钉测试日志 */
        file_put_contents(date("d-H-i-s").'dd-user-info.log',$response);

        $response_data = json_decode($response, true);
        if ($response_data['errcode'] != 0) {
            throw new ThrowException([
                'message' => '获取钉钉用户信息错误错误'
            ]);
        }

        $user_data['userid'] = $response_data['userid'];
        $user_data['department'] = $response_data['department'] ?? '';
        $user_data['name'] = $response_data['name'];
        $user_data['position'] = $response_data['position'] ?? "";

        return $user_data;
    }

    /**
     *  获取部门列表
     */
    public function getDepartmentList()
    {

        $access_token = $this->access_token;
        $url = "https://oapi.dingtalk.com/department/list?access_token={$access_token}";
        $response = file_get_contents($url);

        /* 钉钉测试日志 */
        //file_put_contents(date("d-H-i-s").'dd-bm.log',$response);

        $response_data = json_decode($response, true);
        if ($response_data['errcode'] != 0) {
            throw new ThrowException([
                'message' => '获取钉钉部门列表错误'
            ]);
        }

        if ( $response_data['department'] ) {
            return $response_data['department'];
        } else {
            return [];
        }
    }

    /**
     *  处理部门层级
    */
    public function getDepartmentLevel($data)
    {
        $department = [];
        foreach ($data as $key=>$value) {
            if($value['id']  > 1) {
                $department[] = [
                    'id' => $value['id'],
                    'name' => $value['name'],
                    'parent_id' => $value['parentid']
                ];
            }
        }
        return $this->departmentTree($department);
    }


    /**
     *  权限菜单递归处理
     */
    function departmentTree(array $data, $parent_id = 1) {

        $branch = [];
        foreach ($data as $value) {
            $element = [];
            $element['id'] = $value['id'];
            $element['name'] = $value['name'];
            if ($value['parent_id'] == $parent_id) {
                $children = $this->departmentTree($data, $value['id']);
                if ($children) {
                    array_multisort(array_column($children, 'id'), SORT_ASC, $children);
                    $element['children'] = $children;
                }
                $branch[] = $element;
            }
        }
        return $branch;
    }

    /**
     *  获取部门
    */
    public function getDepartment($departmentList) {

        /* 获取当前部门名称 */
        $currentDepartment = null;
        if( isset($this->user_data['department']) ) {
            $department = $this->user_data['department'];
            $department_id = $department[0];
            foreach ($departmentList as $value) {
                if ( isset($value['id']) ) {
                    if( $value['id'] == $department_id ) {
                        $currentDepartment = $value;
                    }
                }
            }
        }

        /* 获取父级职位名称 */
        if($currentDepartment) {
             $parents = $this->getParents($departmentList,$currentDepartment['id']);
            //$parents = $this->getParents($departmentList, '907468695');

            if (count($parents) == 1) {
                foreach ($parents as $key => $value) {
                    $department = ModelDepartment::where('name', '=', trim($value))->field('id,name')->find();
                    if ($department) {
                        /* 直接返回 */
                        return $department->toArray();
                    } else {
                        /* 新增 */
                        $department = ModelDepartment::create([
                            'name' => trim($value),
                            'pid' => 0,
                            'status' => 1,
                            'create_time' => date("Y-m-d H:i:s", time())
                        ]);
                        if ($department) {
                            return [
                                'id' => $department->id,
                                'name' => $department->name,
                            ];
                        } else {
                            return [];
                        }
                    }
                }
            } else {

                /* 多级部门 */
                $department_ins = [];
                foreach (array_reverse($parents) as $key => $value) {
                    $department = ModelDepartment::where('name', '=', trim($value))->field('id,name')->find();
                    if ($department) {
                        $department = $department->toArray();
                        $department_ins[] = $department;
                    } else {
                        $pid = 0;
                        if ( count($department_ins) > 0 ) {
                            $pid = $department_ins[count($department_ins)-1]['id'];
                        }

                        $departmentCreate = ModelDepartment::create([
                            'name' => trim($value),
                            'pid' => $pid,
                            'status' => 1,
                            'create_time' => date("Y-m-d H:i:s", time())
                        ]);

                        if ( $departmentCreate ) {
                            $departmentCreate = $departmentCreate->toArray();
                            $department_ins[] = [
                                'id' => $departmentCreate['id'],
                                'name' => $departmentCreate['name'],
                            ];
                        }
                    }
                }
                return $department_ins[count($department_ins)-1];
            }
        }

        $department = [];
        foreach( $this->department as $value ) {
            $result = ModelDepartment::where('name','=',trim($value))->field('id,name')->find();
            if( $result ) {
                $department[] = $result['id'];
            } else {
                    $result = ModelDepartment::create([
                    'name' => trim($value),
                    'pid' => 0,
                    'status' => 1,
                    'create_time' => date("Y-m-d H:i:s", time())
                ]);

                $department[] = $result->id;
            }
        }
        return $department;
    }

    /**
     *  钉钉部门导入
    */
    public function departmentImport() {

        $response = <<<EOT
{"errcode":0,"department":[{"ext":"{\"faceCount\":\"76\"}","createDeptGroup":true,"name":"上海明曦信息科技有限公司","id":1,"autoAddUser":true},{"ext":"{\"faceCount\":\"1\"}","createDeptGroup":false,"name":"财务","id":554852758,"autoAddUser":false,"parentid":1},{"ext":"{\"faceCount\":\"46\"}","createDeptGroup":false,"name":"服务器销售","id":555237454,"autoAddUser":false,"parentid":1},{"ext":"{\"faceCount\":\"4\"}","createDeptGroup":false,"name":"其他","id":564857072,"autoAddUser":false,"parentid":1},{"ext":"{\"faceCount\":\"17\"}","createDeptGroup":true,"name":"销售部","id":585414085,"autoAddUser":true,"parentid":555237454},{"ext":"{\"faceCount\":\"3\"}","createDeptGroup":true,"name":"行政管理部","id":585860073,"autoAddUser":true,"parentid":555237454},{"ext":"{\"faceCount\":\"24\"}","createDeptGroup":true,"name":"运营部","id":585878079,"autoAddUser":true,"parentid":555237454},{"ext":"{\"faceCount\":\"3\"}","createDeptGroup":false,"name":"春业路","id":602960286,"autoAddUser":false,"parentid":1},{"ext":"{\"faceCount\":\"8\"}","createDeptGroup":true,"name":"技术开发部","id":701861419,"autoAddUser":true,"parentid":1},{"ext":"{\"faceCount\":\"2\"}","createDeptGroup":true,"name":"供应链","id":703329318,"autoAddUser":true,"parentid":585878079},{"ext":"{\"faceCount\":\"7\"}","createDeptGroup":false,"name":"海外票务部","id":753687338,"autoAddUser":false,"parentid":1},{"createDeptGroup":false,"name":"销售小组","id":907468695,"autoAddUser":false,"parentid":585414085},{"ext":"{\"faceCount\":\"3\"}","createDeptGroup":false,"name":"销售组（出卡）","id":919668614,"autoAddUser":false,"parentid":919922203},{"ext":"{\"faceCount\":\"4\"}","createDeptGroup":false,"name":"商务开拓组","id":919798302,"autoAddUser":false,"parentid":919922203},{"ext":"{\"faceCount\":\"7\"}","createDeptGroup":false,"name":"海外礼品卡部","id":919922203,"autoAddUser":false,"parentid":1},{"createDeptGroup":false,"name":"代销部","id":921093127,"autoAddUser":false,"parentid":555237454},{"ext":"{\"faceCount\":\"2\"}","createDeptGroup":false,"name":"采购部","id":921344828,"autoAddUser":false,"parentid":585878079},{"createDeptGroup":false,"name":"海外合作部","id":972411229,"autoAddUser":false,"parentid":1},{"createDeptGroup":false,"name":"市场部","id":977865824,"autoAddUser":false,"parentid":585878079},{"createDeptGroup":false,"name":"托管业务部","id":980868477,"autoAddUser":false,"parentid":555237454}],"errmsg":"ok"}
EOT;

        $response_data = json_decode($response, true);
        if ($response_data['errcode'] != 0) {
            throw new ThrowException([
                'message' => '获取钉钉部门列表错误'
            ]);
        }

        $departmentList = $this->getDepartmentLevel($response_data['department']);

        Db::startTrans();
        try {
            foreach($departmentList as $key => $value) {
                $result = ModelDepartment::create([
                    'name' => $value['name'],
                    'pid' => 0,
                    'status' => 1,
                    'is_del' => 0,
                    'create_time' => date("Y-m-d H:i:s", time())
                ]);
                if( isset($value['children']) ) {
                    foreach ($value['children'] as $k => $v) {
                        $result2 = ModelDepartment::create([
                            'name' => $v['name'],
                            'pid' => $result['id'],
                            'status' => 1,
                            'is_del' => 0,
                            'create_time' => date("Y-m-d H:i:s", time())
                        ]);
                        if( isset($v['children']) ) {
                            foreach ($v['children'] as $kk => $vv) {
                                ModelDepartment::create([
                                    'name' => $vv['name'],
                                    'pid' => $result2->id,
                                    'status' => 1,
                                    'is_del' => 0,
                                    'create_time' => date("Y-m-d H:i:s", time())
                                ]);
                            }
                        }
                    }
                }
            }
            Db::commit();
            echo 'ok';
        } catch (\Exception $e) {
        // 回滚事务
        Db::rollback();
        echo 'error';
    }
}


    function getParents($array, $id) {
        $result = [];
        foreach ($array as $item) {
            if ($item['id'] == $id) {
                $result[] = $item['name'];
                $parentId = $item['parentid'];
                while ($parentId != 1) {
                    foreach ($array as $parent) {
                        if ($parent['id'] == $parentId) {
                            $result[] = $parent['name'];
                            $parentId = $parent['parentid']??1;
                            break;
                        }
                    }
                }
                return $result;
            }
        }
        return $result;
    }


}
